// Transparency/Blending states from: http://www.braynzarsoft.net/index.php?p=D3D11BLENDING
// and: http://rastertek.com/tertut11.html
// Date referenced February 19th 2013

#ifndef SCREENMANAGER_H
#define SCREENMANAGER_H

#include "Resource.h"
#include "Singleton.h"
#include "ObjMeshManager.h"
#include "DX11VertexData.h"
#include "ConstantBuffer.h"

#include <vector>
#include <windows.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dcompiler.h>
#include <D3DX10math.h>

class ScreenManager : public Uncopyable
{
	ScreenManager();
	friend class Singleton<ScreenManager>;
public:
	WPARAM CreateDX11Window(const HINSTANCE& hInstance, const HINSTANCE& hPrevInstance, 
		const LPWSTR& lpCmdLine, const int& nCmdShow);

	ID3D11Device* GetDevice() {return m_pd3dDevice;}
	ID3D11DeviceContext* GetDeviceContext() {return m_pImmediateContext;}
	ID3D11RenderTargetView** GetRenderTargetview() {return &m_pRenderTargetView;}
	ID3D11DepthStencilView* GetDepthStencilView() {return m_pDepthStencilView;}
	ID3D11DepthStencilState* GetDepthStateState() {return m_pDepthStencilState;}
	ID3D11Texture2D* GetDepthStencilBuffer();

	// different stencil state draw modes
	void SetFrontBackDrawStencilState();
	void SetDefaultStencilState();
	void SetCullNoneRasteriserState();

	ID3D11Buffer* GetConstantBuffer() {return m_pConstantBuffer;}
	void SetConstantBuffer(ID3D11Buffer* constBuffer);
	
	D3D_DRIVER_TYPE& GetDriverType() {return m_driverType;}

	D3DXMATRIX& GetWorldMatrix() {return m_world;}
	D3DXMATRIX& GetViewMatrix() {return m_view;}
	D3DXMATRIX& GetProjectionMatrix() {return m_projection;}

	// need shader loads too
	HRESULT InitBuffers(ID3D11Buffer*& vertBuffer, ID3D11Buffer*& indexBuffer, D3D11_BUFFER_DESC& bd, 
	D3D11_SUBRESOURCE_DATA& initData, const std::vector<VertexData>& vertData, const std::vector<DWORD>& indexData,
	ID3D11Buffer** cb);
	
	// alpha blending
	void EnableBlending();
	void EnableBlendingNB();
	void DisableBlending();

	IDXGISwapChain*& GetSwapChain() {return m_pSwapChain;}

	void SetBuffers(ID3D11Buffer*& vertBuffer, ID3D11Buffer*& indexBuffer);

	HWND GetWindowHandler() const {return m_hWnd;} 

	void FlipBuffers();

	void SetViewMatrix(const D3DXVECTOR3& pos, const D3DXVECTOR3& target, const D3DXVECTOR3& up);
	void SetViewMatrix(const D3DXMATRIX& view);
	void SetViewProjMatrix(const D3DXMATRIX& view, const D3DXMATRIX& proj);
	void SetBEV(const D3DXMATRIX& view);

	void SetWindowSize(int width, int height);
	int GetWindowHeight();
	int GetWindowWidth();
	float GetAspectRatio();

private: // private functions
	void UpdateCamera();

	HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow);
	HRESULT InitDevice();
	void CleanupDevice();
	void GameLoop();

private: // private variables
	HINSTANCE               m_hInst;
	HWND                    m_hWnd;
	D3D_DRIVER_TYPE         m_driverType;
	D3D_FEATURE_LEVEL       m_featureLevel;
	ID3D11Device*           m_pd3dDevice;
	ID3D11DeviceContext*    m_pImmediateContext;
	IDXGISwapChain*         m_pSwapChain;
	ID3D11RenderTargetView* m_pRenderTargetView;
	ID3D11DepthStencilView* m_pDepthStencilView;
	ID3D11DepthStencilState* m_pDepthStencilState;
	ID3D11Texture2D*		m_pDepthStencilBuffer;
	ID3D11Buffer*			m_pConstantBuffer;
	ID3D11DepthStencilState* m_pNoDepthStencilState; // front + back face draw
	//D3D11_RASTERIZER_DESC m_rasteriser;
	ID3D11RasterizerState* m_pNoCullingRasteriserState;
	ID3D11RasterizerState* m_pCullingRasteriserState;
	ID3D11RasterizerState* m_pCullNoneRasiterserState;

	//ID3D11VertexShader*     m_pVertexShader;
	//ID3D11PixelShader*      m_pPixelShader;

	// game state variables
	D3DXMATRIX m_world;
	D3DXMATRIX m_view;
	D3DXMATRIX m_projection;

	int m_height;
	int m_width;

	ID3D11RasterizerState* m_pRasterizerState;
	D3D11_RASTERIZER_DESC m_rasterizerDesc;

	// alpha vars
	ID3D11BlendState* m_pTransparencyBlendState;
	ID3D11BlendState* m_pTransparencyBlendStateNB;
	//ID3D11RasterizerState* m_p
};

typedef Singleton<ScreenManager> TheScreenManager;

#endif //SCREENMANAGER_H